/**
 * This file is part of Adaptools.
 * 
 * Adaptools is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Adaptools is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 * along with Adaptools.  If not, see http://www.gnu.org/licenses/. 
 */
package org.adaptools.base;

import org.adaptools.base.exception.AdaptoolsException;
import org.adaptools.base.utils.AdaptoolsBaseMessages;
import org.apache.log4j.Logger;

/**
 * This class has great importance to the system. It is responsible to create
 * and transport all system rules during all the time of live..
 * 
 * @author Denys G. Santos (gsdenys@gmail.com)
 * @since 3.0.0
 */
public class BasicRule implements Rule {
	private Logger LOG = Logger.getLogger(BasicRule.class);

	/**
	 * The UUID of Rule. This attribute should <b>NOT</b> be assigned directly
	 * here. It is responsibility of Your selected <b>REPOSITORY MODULE</b>.
	 */
	private String id = null;

	/**
	 * The Rule header.It is used to give the name to the sub-machine or
	 * adaptive function contained in the Rule.
	 * 
	 * When the content of this column was a adaptive function, this will be
	 * identified by elementary adaptive actions, that can be query (?),
	 * insertion (+) and delete (-).
	 */
	private String header = null;

	/**
	 * The Rule source. It maintain a identifier that represent the source of
	 * device.
	 */
	private String source = null;

	/**
	 * The Rule input. It maintain the symbol that can be read from the queue
	 * stating from source state.
	 */
	private String input = null;

	/**
	 * The Rule target. It's maintain a identifier that represent the target of
	 * device.
	 */
	private String target = null;

	/**
	 * The Rule push. This column is used in sub-machine calls, to indicate the
	 * return state. Sub-machine returns are indicated by the reserved keyword
	 * <b>pop</b> placed in the destination state column
	 * 
	 * The reserved keyword <b><i>nop</i></b> may be used anywhere to indicate
	 * that the column is not being used.
	 */
	private String push = null;

	/**
	 * The Rule output. this is used to sent a symbol or string to the system
	 * output.
	 * 
	 * The reserved keyword <b><i>nop</i></b> may be used anywhere to indicate
	 * that the column is not being used.
	 */
	private String output = null;

	/**
	 * The last column, for adaptive action, is used to link a transition to a
	 * pair of adaptive functions and contains a string with the form
	 * <b>B.A</p>, where <b>B</b> and <b>A</b> are names of adaptive functions
	 * that are to be executed <b>B</b>efore and <b>A</b>fter the transition
	 * (any one of them may be omitted).
	 * 
	 * The reserved keyword <b><i>nop</i></b> may be used anywhere to indicate
	 * that the column is not being used.
	 */
	private String adaptive = null;

	/**
	 * Default Builder
	 */
	public BasicRule() {
	}

	/**
	 * @see org.adaptools.base.Rule#populateRule(String, String, String, String,
	 *      String, String, String)
	 */
	public void populateRule(String header, String source, String input,
			String target, String push, String output, String adaptive)
			throws AdaptoolsException {

		// Validate Header Value
		if (header == null || header.trim().equals("")) {
			// get the message id and Value
			String id = AdaptoolsBaseMessages.ERROR_ERROR_HEADER_IS_REQUIRED
					.getId();

			LOG.error("ERROR " + id + ": Header is required.");

			// throws a new Adaptools Exception
			throw new AdaptoolsException(id);
		}

		// Validate source value
		if (source == null || source.trim().equals("")) {
			// get the message id and Value
			String id = AdaptoolsBaseMessages.ERROR_SOURCE_IS_REQUIRED.getId();

			LOG.error("ERROR " + id + ": Source is required.");

			// throws a new Adaptools Exception
			throw new AdaptoolsException(id);
		}

		// Validate input Value
		if (input == null || input.trim().equals("")) {
			// get the message id and Value
			String id = AdaptoolsBaseMessages.ERROR_INPUT_IS_REQUIRED.getId();

			LOG.error("ERROR " + id + ": Input is required.");

			// throws a new Adaptools Exception
			throw new AdaptoolsException(id);
		}

		// validate target value
		if (target == null || target.trim().equals("")) {
			// get the message id and Value
			String id = AdaptoolsBaseMessages.ERROR_TARGET_IS_REQUIRED.getId();

			LOG.error("ERROR " + id + ": Target is required.");

			// throws a new Adaptools Exception
			throw new AdaptoolsException(id);
		}

		this.header = header;
		this.source = source;
		this.input = input;
		this.target = target;

		// Verify push
		if (push == null) {
			this.push = ReservedWords.COLUMN_NOT_OPERATE.getLabel();
		} else {
			this.push = push;
		}

		// verify output
		if (output == null) {
			this.output = ReservedWords.COLUMN_NOT_OPERATE.getLabel();
		} else {
			this.output = output;
		}

		// verify adaptive
		if (adaptive == null) {
			this.adaptive = ReservedWords.COLUMN_NOT_OPERATE.getLabel();
		} else {
			this.adaptive = adaptive;
		}
	}

	/**
	 * Partial Builder. This builder create just the rule basic values
	 * 
	 * @param header
	 * @param source
	 * @param input
	 * @param target
	 */
	public void populateRule(String header, String source, String input,
			String target) throws AdaptoolsException {

		this.populateRule(header, source, input, target, null, null, null);
	}

	/**
	 * @see org.adaptools.base.Rule#getId()
	 */
	public String getId() {
		return id;
	}

	/**
	 * @see org.adaptools.base.Rule#setId(String)
	 */
	public void setId(String id) {
		this.id = id;
	}

	/**
	 * @see org.adaptools.base.Rule#getHeader()
	 */
	public String getHeader() {
		return header;
	}

	/**
	 * @see org.adaptools.base.Rule#setHeader(String)
	 */
	public void setHeader(String header) {
		this.header = header;
	}

	/**
	 * @see org.adaptools.base.Rule#getSource()
	 */
	public String getSource() {
		return source;
	}

	/**
	 * @see org.adaptools.base.Rule#setSource(String)
	 */
	public void setSource(String source) {
		this.source = source;
	}

	/**
	 * @see org.adaptools.base.Rule#getInput()
	 */
	public String getInput() {
		return input;
	}

	/**
	 * @see org.adaptools.base.Rule#setInput(String)
	 */
	public void setInput(String input) {
		this.input = input;
	}

	/**
	 * @see org.adaptools.base.Rule#getTarget()
	 */
	public String getTarget() {
		return target;
	}

	/**
	 * @see org.adaptools.base.Rule#setTarget(String)
	 */
	public void setTarget(String target) {
		this.target = target;
	}

	/**
	 * @see org.adaptools.base.Rule#getPush()
	 */
	public String getPush() {
		return push;
	}

	/**
	 * @see org.adaptools.base.Rule#setPush(String)
	 */
	public void setPush(String push) {
		this.push = push;
	}

	/**
	 * @see org.adaptools.base.Rule#getOutput()
	 */
	public String getOutput() {
		return output;
	}

	/**
	 * @see org.adaptools.base.Rule#setOutput(String)
	 */
	public void setOutput(String output) {
		this.output = output;
	}

	/**
	 * @see org.adaptools.base.Rule#getAdaptive()
	 */
	public String getAdaptive() {
		return adaptive;
	}

	/**
	 * @see org.adaptools.base.Rule#setAdaptive(String)
	 */
	public void setAdaptive(String adaptive) {
		this.adaptive = adaptive;
	}

	/**
	 * @see org.adaptools.base.Rule#isAdaptiveRule()
	 */
	public boolean isAdaptiveRule() {
		if (this.getHeader().startsWith(
				AdaptiveSymbols.ADAPTIVE_ADD_SYMBOL.getSimbol())) {
			return true;
		}

		if (this.getHeader().startsWith(
				AdaptiveSymbols.ADAPTIVE_REMOVE_SYMBOL.getSimbol())) {
			return true;
		}

		if (this.getHeader().startsWith(
				AdaptiveSymbols.ADAPTIVE_SEARCH_SYMBOL.getSimbol())) {
			return true;
		}

		return false;
	}

	/**
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		StringBuilder rule = new StringBuilder();

		rule.append(this.getHeader());
		rule.append(";");
		rule.append(this.getSource());
		rule.append(";");
		rule.append(this.getInput());
		rule.append(";");
		rule.append(this.getTarget());
		rule.append(";");
		rule.append(this.getPush());
		rule.append(";");
		rule.append(this.getOutput());
		rule.append(";");
		rule.append(this.getAdaptive());
		rule.append(";");

		return rule.toString();
	}
	
	/**
	 * @see org.adaptools.base.Copyable#copy()
	 */
	@Override
	public Rule copy() {
		Rule rule = new BasicRule();

		rule.setHeader(this.header);
		rule.setInput(this.input);
		rule.setSource(this.source);
		rule.setTarget(this.target);
		rule.setOutput(this.output);
		rule.setPush(this.push);
		rule.setAdaptive(this.adaptive);

		return rule;
	}

}